﻿using ELTE.SEM.Data.ViewModels;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;

namespace ELTE.SEM.Data.Repository
{
    public class FolderRepository : Repository<SemFolder>, IFolderRepository
    {

        public FolderRepository(DbContext context) : base(context) { }

        public SemFolderViewModel GetFolders()
        {
            SemFolderViewModel result = null;
            try
            {
                var allFolders = GetAll().ToList();
                //minden egyes folder-hez kell, hogy kik a gyerekei
                SemFolder rootFolder = allFolders.SingleOrDefault(f => !f.ParentFolderId.HasValue);
                if (rootFolder == null)
                {
                    return null;
                }
                else
                {
                    //result = new SemFolderViewModel
                    //{
                    //    Id = rootFolder.Id,
                    //    FolderName = rootFolder.FolderName,
                    //    Children = GetAllChildren(allFolders, rootFolder)
                    //};
                    result = rootFolder.GetViewModel(null);
                    return result;
                }
            }
            catch (Exception ex)
            {

            }
            return result;
        }

        public List<SemFolderAccessViewModel> GetFolderAccesses(int userId)
        {
            List<SemFolderAccessViewModel> folders = new List<SemFolderAccessViewModel>();
            try
            {
                List<SemFolder> allFolders = this.DbSet.ToList();
                folders = allFolders.Select(folder =>
                new SemFolderAccessViewModel
                {
                    Folder = GetFolderViewModel(folder.Id, allFolders),
                    HasAccess = folder.UserFolderAccesses.Count == 0 ? false : (folder.UserFolderAccesses.Any(ufa => ufa.UserId == userId) ? folder.UserFolderAccesses.SingleOrDefault(ufa => ufa.UserId == userId).HasAccess : false),
                }
                ).ToList();
            }
            catch (Exception ex)
            {

            }

            return folders;

        }

        private SemFolderViewModel GetFolderViewModel(int folderId, List<SemFolder> allFolders)
        {
            try
            {
                SemFolder folder = allFolders.SingleOrDefault(f => f.Id == folderId);
                if (folder != null)
                {
                    return new SemFolderViewModel
                    {
                        FolderName = folder.FolderName,
                        Id = folder.Id,
                        Parent = folder.ParentFolderId.HasValue ? GetFolderViewModel(folder.ParentFolderId.Value, allFolders) : null,
                        FullPath = folder.FullPath,
                    };
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                return null;
            }

        }

        public bool IsAccessibleFor(string userName, int folderId)
        {
            SemFolder folder = GetById(folderId);
            if (folder != null)
            {
                return folder.UserFolderAccesses.Any(ufa => ufa.User.Name == userName);
            }
            else
            {
                return false;
            }
        }

        public SemFolderViewModel GetRootFolderViewModel(List<SemDataViewModel> foldersData, string rootFolderPath)
        {
            try
            {
                //minden egyes elemen végigmegyünk.
                //kezdéshez kell a gyökérelem, vagyis amelyikhez nincs szülő beállítva.
                var folders = GetAll();
                //SemFolder rootFromDB = folders.SingleOrDefault(folder => !folder.ParentFolderId.HasValue);
                SemDataViewModel rootViewModel = foldersData.SingleOrDefault(fd => fd.ParentFolder == rootFolderPath);

                SemFolderViewModel rootFolderViewModel = null;
                SemFolder altRootDB = GetAll().SingleOrDefault(f => f.Parent == null);
                if (altRootDB != null)
                {
                    rootFolderViewModel = altRootDB.GetViewModel(null);
                }
                else
                {
                    rootFolderViewModel = new SemFolderViewModel
                    {
                        FolderName = rootViewModel.Name,
                        Children = new List<SemFolderViewModel>(),
                        FullPath = rootFolderPath.Contains(rootViewModel.Name) ? rootFolderPath : String.Concat(rootFolderPath, "/", rootViewModel.Name),
                        Id = -1,
                        Parent = null,
                    };
                    //a kapott listából kellenek a gyerekei
                    rootFolderViewModel.Children = GetAllChildren(foldersData, rootFolderViewModel);

                }
                //a folyamat rekurzív, innen könnyen megkapható a teljes könyvtárstruktúra.
                return rootFolderViewModel;
            }
            catch (Exception ex)
            {
                //TODO: log error
                return null;
            }

        }


        public bool AddFolders(SemFolderViewModel rootFolderViewModel)
        {
            bool result = true;
            try
            {
                if (rootFolderViewModel != null)
                {
                    //minden egyes könyvtárra ellenőrizni kell, hogy megtalálható-e az adatbázisban.

                    AddFolderWithChildren(rootFolderViewModel, null);
                }

            }
            catch (Exception ex)
            {
                //TODO : Error logging
                result = false;
            }
            return result;

        }

        private List<SemFolderViewModel> GetAllChildren(List<SemFolder> allFolders, SemFolder currentFolder)
        {
            List<SemFolderViewModel> children = allFolders
                .Where(f => f.ParentFolderId.HasValue && f.ParentFolderId.Value == currentFolder.Id)
                .Select(subfolder =>
                    new SemFolderViewModel
                    {
                        Id = subfolder.Id,
                        FolderName = subfolder.FolderName,
                        Children = GetAllChildren(allFolders, subfolder)
                    }).ToList();
            return children;
        }

        private List<SemFolderViewModel> GetAllChildren(List<SemDataViewModel> allFolders, SemFolderViewModel currentFolder)
        {
            List<SemFolderViewModel> children = new List<SemFolderViewModel>();
            var childFolders = allFolders
                .Where(f => f.ParentFolder.EndsWith(currentFolder.FolderName))
                .ToList();
            allFolders.RemoveAll(f => childFolders.Contains(f));

            childFolders.ForEach(f =>
                {
                    SemFolderViewModel child = new SemFolderViewModel
                    {
                        FolderName = f.Name,
                        Parent = currentFolder,
                        //ŰFullPath = 
                    };
                    child.Children = GetAllChildren(allFolders, child);
                    children.Add(child);
                });
            return children;
        }

        private int AddFolder(SemFolderViewModel folder, int? parentFolderId)
        {
            try
            {
                SemFolder newFolder = new SemFolder
                {
                    FolderName = folder.FolderName,
                    ParentFolderId = parentFolderId,
                    FullPath = folder.GetPath(),
                };
                Insert(newFolder);

                Save();
                return newFolder.Id;
            }
            catch (Exception ex)
            {
                return 0;
            }


        }

        private void AddFolderWithChildren(SemFolderViewModel folder, int? parentFolderId)
        {
            try
            {
                int? addedFolderId = null;
                //leellenőrizzük, hogy az adott könyvtár megtalálható-e az adatbázisban
                //azt vizsgáljuk, hogy az adott könyvtár nevével található-e könyvtár, 
                //melynek ugyanannyi gyereke van mint az aktuálisan vizsgáltnak
                var allFolders = GetAll();
                int childCount = folder.Children.Count;
                var foldersWithSameName = allFolders.Where(f => f.FolderName == folder.FolderName);
                //var foldersWithSameNameAndChildrenCount = foldersWithSameName.Where(f => 
                //    //f.ParentFolderId == parentFolderId
                //    (parentFolderId.HasValue && f.ParentFolderId.HasValue) ? parentFolderId.Value == f.ParentFolderId.Value : false
                //    );
                //check full path
                var foldersWithSamePath = foldersWithSameName.Where(f => f.FullPath == folder.FullPath);
                if (foldersWithSamePath.Count() == 0)
                {
                    addedFolderId = AddFolder(folder, parentFolderId);
                }
                else
                {
                    //a könyvtár már hozzá lett adva
                    addedFolderId = foldersWithSamePath.First().Id;
                }
                if (addedFolderId.HasValue && addedFolderId.Value > 0)
                {
                    foreach (var child in folder.Children)
                    {
                        AddFolderWithChildren(child, addedFolderId);
                    }
                }



            }
            catch (Exception ex)
            {

            }

        }

        public bool SetFolderAccess(int folderId, int userId, bool HasAccess)
        {
            bool result = true;
            try
            {
                SemFolder folder = GetById(folderId);
                if (folder != null)
                {
                    UserFolderAccess folderAccess = folder.UserFolderAccesses.SingleOrDefault(ufa => ufa.UserId == userId);
                    if (folderAccess != null)
                    {
                        //van már könyvtárhozzáférés beállítva
                        folderAccess.HasAccess = HasAccess;
                    }
                    else
                    {
                        //könyvtárhozzáférés még nincs beállítva
                        folder.UserFolderAccesses.Add(new UserFolderAccess
                        {
                            FolderId = folderId,
                            UserId = userId,
                            HasAccess = HasAccess,
                        });
                    }
                }
                else
                {
                    //TODO: log the error
                    result = false;
                }
            }
            catch (Exception ex)
            {
                //TODO: log error
                result = false;
            }
            return result;
        }
    }
}
